package com.tangcheng.adapter.db.mybatis.plugin.sensitive.processor;

import com.tangcheng.adapter.db.mybatis.plugin.sensitive.annotation.SensitiveField;
import com.tangcheng.adapter.db.mybatis.plugin.sensitive.service.IEncryptionAlgorithm;
import com.tangcheng.adapter.db.mybatis.plugin.sensitive.util.FieldHelper;
import org.aspectj.lang.ProceedingJoinPoint;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public abstract class AbstractSensitiveField {

    protected IEncryptionAlgorithm encryptService;

    public AbstractSensitiveField() {
    }

    public abstract Object proceed(ProceedingJoinPoint proceedingJoinPoint) throws Throwable;

    public abstract void setFieldValue(Object object, Field field);

    public Object handleSingleObject(Object o) {
        if (o == null) {
            return null;
        }
        List<Field> allDeclaredFields = getAllDeclaredFields(o.getClass());
        for (Field field : allDeclaredFields) {
            if (field.isAnnotationPresent(SensitiveField.class)) {
                if (FieldHelper.checkIfObject(field.getType().getName())) {
                    try {
                        field.setAccessible(true);
                        Object object = field.get(o);
                        if (object instanceof List) {
                            List list = (List) object;
                            this.handleList(list);
                        } else if (FieldHelper.checkIfObject(object.getClass().getTypeName())) {
                            this.handleSingleObject(object);
                        } else {
                            this.setFieldValue(o, field);
                        }

                        field.setAccessible(false);
                    } catch (Exception ignored) {
                    }
                } else {
                    this.setFieldValue(o, field);
                }
            }
        }
        return o;
    }

    public List handleList(List list) {
        List retList = new ArrayList(list.size());
        Iterator iterator = list.iterator();

        while (iterator.hasNext()) {
            Object o = iterator.next();
            Object map = this.handleSingleObject(o);
            retList.add(map);
        }

        return retList;
    }

    public Set handleSet(Set set) {
        Set resultSet = new HashSet(set.size());
        set.forEach((item) -> {
            Object o = this.handleSingleObject(item);
            resultSet.add(o);
        });
        return resultSet;
    }


    public static List<Field> getAllDeclaredFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        while (clazz != null) {
            Field[] declaredFields = clazz.getDeclaredFields();
            fields.addAll(Arrays.asList(declaredFields));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }


}
